/**
 ******************************************************************************
 * @file           : bsp_iic.c
 * @brief          : Hardware I2C Driver Implementation (STM32F4xx)
 ******************************************************************************
 * @attention
 *
 * 硬件I2C驱动实现文件
 * 使用GPIO AF复用功能 + HAL库I2C驱动
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/IIC/bsp_iic.h"
#include "./BSP/IIC/bsp_iic_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static I2C_HandleTypeDef sg_iic_handle;

/* Private function prototypes -----------------------------------------------*/
static void iic_gpio_init(void);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       I2C GPIO初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        STM32F4xx使用GPIO AF复用功能
 */
static void iic_gpio_init(void)
{
    GPIO_InitTypeDef gpio_init_struct = {0};

    /* 使能GPIO时钟 */
    IIC_SCL_GPIO_CLK_ENABLE();
    IIC_SDA_GPIO_CLK_ENABLE();

    /* 配置SCL引脚（复用开漏输出） */
    gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_OD;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    gpio_init_struct.Alternate = IIC_GPIO_AF;  /* 配置AF功能 */
    HAL_GPIO_Init(IIC_SCL_GPIO_PORT, &gpio_init_struct);

    /* 配置SDA引脚（复用开漏输出） */
    gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_OD;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    gpio_init_struct.Alternate = IIC_GPIO_AF;  /* 配置AF功能 */
    HAL_GPIO_Init(IIC_SDA_GPIO_PORT, &gpio_init_struct);
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       硬件I2C初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        初始化I2C外设和GPIO
 */
void iic_init(void)
{
    /* 使能I2C时钟 */
    IIC_I2Cx_CLK_ENABLE();

    /* 初始化GPIO */
    iic_gpio_init();

    /* 配置I2C */
    sg_iic_handle.Instance = IIC_I2Cx;
    sg_iic_handle.Init.ClockSpeed = IIC_SPEED;
    sg_iic_handle.Init.DutyCycle = I2C_DUTYCYCLE_2;
    sg_iic_handle.Init.OwnAddress1 = 0x00;

#if (IIC_ADDR_MODE == 7)
    sg_iic_handle.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
#else
    sg_iic_handle.Init.AddressingMode = I2C_ADDRESSINGMODE_10BIT;
#endif

    sg_iic_handle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    sg_iic_handle.Init.OwnAddress2 = 0x00;
    sg_iic_handle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    sg_iic_handle.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;

    /* 初始化I2C外设 */
    if (HAL_I2C_Init(&sg_iic_handle) != HAL_OK)
    {
        log_e("I2C%d initialization failed", IIC_SELECT_NUM);
        return;
    }

    log_i("I2C%d initialized: %dkHz", IIC_SELECT_NUM, IIC_SPEED / 1000);
}

/**
 * @brief       I2C去初始化
 *
 * @param       无
 *
 * @retval      无
 */
void iic_deinit(void)
{
    /* 去初始化I2C */
    HAL_I2C_DeInit(&sg_iic_handle);

    log_i("I2C%d deinitialized", IIC_SELECT_NUM);
}

/**
 * @brief       写单个寄存器
 *
 * @param[in]   dev_addr 设备地址（7位地址<<1）
 * @param[in]   reg_addr 寄存器地址
 * @param[in]   data 要写入的数据
 *
 * @retval      0=成功，1=失败
 */
uint8_t iic_write_reg(uint8_t dev_addr, uint8_t reg_addr, uint8_t data)
{
    uint8_t buf[2];

    buf[0] = reg_addr;
    buf[1] = data;

    if (HAL_I2C_Master_Transmit(&sg_iic_handle, dev_addr, buf, 2, IIC_TIMEOUT_MS) != HAL_OK)
    {
        log_e("I2C write reg failed: dev=0x%02X, reg=0x%02X", dev_addr, reg_addr);
        return 1;
    }

    return 0;
}

/**
 * @brief       读单个寄存器
 *
 * @param[in]   dev_addr 设备地址（7位地址<<1）
 * @param[in]   reg_addr 寄存器地址
 * @param[out]  data 读取的数据
 *
 * @retval      0=成功，1=失败
 */
uint8_t iic_read_reg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data)
{
    if (data == NULL)
    {
        return 1;
    }

    /* 发送寄存器地址 */
    if (HAL_I2C_Master_Transmit(&sg_iic_handle, dev_addr, &reg_addr, 1, IIC_TIMEOUT_MS) != HAL_OK)
    {
        log_e("I2C write reg addr failed: dev=0x%02X, reg=0x%02X", dev_addr, reg_addr);
        return 1;
    }

    /* 读取数据 */
    if (HAL_I2C_Master_Receive(&sg_iic_handle, dev_addr, data, 1, IIC_TIMEOUT_MS) != HAL_OK)
    {
        log_e("I2C read reg failed: dev=0x%02X, reg=0x%02X", dev_addr, reg_addr);
        return 1;
    }

    return 0;
}

/**
 * @brief       写多个字节
 *
 * @param[in]   dev_addr 设备地址（7位地址<<1）
 * @param[in]   reg_addr 寄存器地址
 * @param[in]   buf 要写入的数据缓冲区
 * @param[in]   len 数据长度
 *
 * @retval      0=成功，1=失败
 */
uint8_t iic_write_bytes(uint8_t dev_addr, uint8_t reg_addr, uint8_t *buf, uint16_t len)
{
    uint8_t *temp_buf = NULL;
    uint8_t result;

    if (buf == NULL || len == 0)
    {
        return 1;
    }

    /* 分配临时缓冲区（寄存器地址+数据） */
    temp_buf = (uint8_t *)malloc(len + 1);
    if (temp_buf == NULL)
    {
        log_e("Memory allocation failed");
        return 1;
    }

    /* 填充寄存器地址和数据 */
    temp_buf[0] = reg_addr;
    for (uint16_t i = 0; i < len; i++)
    {
        temp_buf[i + 1] = buf[i];
    }

    /* 发送数据 */
    if (HAL_I2C_Master_Transmit(&sg_iic_handle, dev_addr, temp_buf, len + 1, IIC_TIMEOUT_MS) != HAL_OK)
    {
        log_e("I2C write bytes failed: dev=0x%02X, reg=0x%02X, len=%u", dev_addr, reg_addr, len);
        result = 1;
    }
    else
    {
        result = 0;
    }

    /* 释放缓冲区 */
    free(temp_buf);

    return result;
}

/**
 * @brief       读多个字节
 *
 * @param[in]   dev_addr 设备地址（7位地址<<1）
 * @param[in]   reg_addr 寄存器地址
 * @param[out]  buf 读取的数据缓冲区
 * @param[in]   len 数据长度
 *
 * @retval      0=成功，1=失败
 */
uint8_t iic_read_bytes(uint8_t dev_addr, uint8_t reg_addr, uint8_t *buf, uint16_t len)
{
    if (buf == NULL || len == 0)
    {
        return 1;
    }

    /* 发送寄存器地址 */
    if (HAL_I2C_Master_Transmit(&sg_iic_handle, dev_addr, &reg_addr, 1, IIC_TIMEOUT_MS) != HAL_OK)
    {
        log_e("I2C write reg addr failed: dev=0x%02X, reg=0x%02X", dev_addr, reg_addr);
        return 1;
    }

    /* 读取数据 */
    if (HAL_I2C_Master_Receive(&sg_iic_handle, dev_addr, buf, len, IIC_TIMEOUT_MS) != HAL_OK)
    {
        log_e("I2C read bytes failed: dev=0x%02X, reg=0x%02X, len=%u", dev_addr, reg_addr, len);
        return 1;
    }

    return 0;
}

/**
 * @brief       检测I2C设备是否存在
 *
 * @param[in]   dev_addr 设备地址（7位地址<<1）
 *
 * @retval      0=存在，1=不存在
 */
uint8_t iic_check_device(uint8_t dev_addr)
{
    uint8_t result;

    if (HAL_I2C_IsDeviceReady(&sg_iic_handle, dev_addr, 3, IIC_TIMEOUT_MS) == HAL_OK)
    {
        result = 0;
        log_d("I2C device 0x%02X: OK", dev_addr);
    }
    else
    {
        result = 1;
        log_d("I2C device 0x%02X: Not Found", dev_addr);
    }

    return result;
}

/**
 * @brief       主机发送数据（无寄存器地址）
 *
 * @param[in]   dev_addr 设备地址
 * @param[in]   data 数据指针
 * @param[in]   len 数据长度
 *
 * @retval      IIC_OK - 成功
 * @retval      IIC_ERROR_PARAM - 参数错误
 * @retval      IIC_ERROR_TIMEOUT - 超时
 */
IIC_Error_e iic_master_transmit(uint16_t dev_addr, const uint8_t *data, uint16_t len)
{
    if (data == NULL || len == 0)
    {
        return IIC_ERROR_PARAM;
    }

    if (HAL_I2C_Master_Transmit(&sg_iic_handle, (uint16_t)dev_addr, (uint8_t *)data, len, IIC_TIMEOUT_MS) != HAL_OK)
    {
        return IIC_ERROR_TIMEOUT;
    }

    return IIC_OK;
}

/**
 * @brief       主机接收数据（无寄存器地址）
 *
 * @param[in]   dev_addr 设备地址
 * @param[out]  data 数据指针
 * @param[in]   len 数据长度
 *
 * @retval      IIC_OK - 成功
 * @retval      IIC_ERROR_PARAM - 参数错误
 * @retval      IIC_ERROR_TIMEOUT - 超时
 */
IIC_Error_e iic_master_receive(uint16_t dev_addr, uint8_t *data, uint16_t len)
{
    if (data == NULL || len == 0)
    {
        return IIC_ERROR_PARAM;
    }

    if (HAL_I2C_Master_Receive(&sg_iic_handle, (uint16_t)dev_addr, data, len, IIC_TIMEOUT_MS) != HAL_OK)
    {
        return IIC_ERROR_TIMEOUT;
    }

    return IIC_OK;
}

/**
 * @brief       检查设备是否就绪
 *
 * @param[in]   dev_addr 设备地址
 * @param[in]   retry 重试次数
 *
 * @retval      IIC_OK - 设备就绪
 * @retval      IIC_ERROR_TIMEOUT - 设备不就绪
 */
IIC_Error_e iic_is_device_ready(uint16_t dev_addr, uint8_t retry)
{
    if (HAL_I2C_IsDeviceReady(&sg_iic_handle, (uint16_t)dev_addr, retry, IIC_TIMEOUT_MS) == HAL_OK)
    {
        return IIC_OK;
    }

    return IIC_ERROR_TIMEOUT;
}

/**
 * @brief       扫描 I2C总线，找出所有设备
 *
 * @param       无
 *
 * @retval      无
 */
void iic_scan_bus(void)
{
    uint8_t addr;
    uint8_t count = 0;

    log_i("I2C Bus Scan:");
    
    for (addr = 0x01; addr < 0x7F; addr += 2)
    {
        if (iic_is_device_ready(addr, 1) == IIC_OK)
        {
            log_i("  Found device at 0x%02X", addr);
            count++;
        }
    }

    log_i("Total devices found: %d", count);
}

/**
 * @brief       获取错误描述字符串
 *
 * @param[in]   error 错误码
 *
 * @retval      错误描述字符串
 */
const char* iic_get_error_string(IIC_Error_e error)
{
    static const char *error_str[] = {
        "IIC_OK",
        "IIC_ERROR_PARAM",
        "IIC_ERROR_TIMEOUT",
        "IIC_ERROR_BUSY",
        "IIC_ERROR_NACK",
        "IIC_ERROR_AF",
        "IIC_ERROR_BERR",
        "IIC_ERROR_ARLO",
        "IIC_ERROR_OVR",
        "IIC_ERROR"
    };

    if (error < 10)
    {
        return error_str[error];
    }

    return "IIC_ERROR_UNKNOWN";
}
